package com.heo.music.player.config.swagger;

import com.fasterxml.classmate.TypeResolver;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.builders.ResponseMessageBuilder;
import springfox.documentation.schema.AlternateTypeRule;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.service.ResponseMessage;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;

/**
 * @author 星天无极
 **/
@Configuration
@Slf4j
@RequiredArgsConstructor
@EnableSwagger2WebMvc
public class SwaggerConfig {

    private final TypeResolver typeResolver;


    @Bean
    public ApiInfo apiInfo() {
        return new ApiInfoBuilder()
            .title("音乐管理接口")
            .description("音乐管理API文档")
            .contact(new Contact("Liu Kang", "", "liukang@ctjsoft.com"))
            .version("1.0.0")
            .build();
    }

    @Bean
    public Docket createEvRestApi(Environment env, ApiInfo apiInfo) {
        log.info("启用Swagger");
        return setResponseMessages(new Docket(DocumentationType.SWAGGER_2))
            .apiInfo(apiInfo)
            .select()
            .apis(RequestHandlerSelectors.withClassAnnotation(Api.class)
                                         .and(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
                                         .and(RequestHandlerSelectors.basePackage("com.heo.music.player.controller"))
            )
            .paths(PathSelectors.any())
            .build()
            .alternateTypeRules(
                new AlternateTypeRule(typeResolver.resolve(ResponseEntity.class, byte[].class),
                    typeResolver.resolve(MultipartFile.class))
            );
    }

    public Docket setResponseMessages(Docket docket) {
        final ResponseMessage badRequestResponse = new ResponseMessageBuilder()
            .code(HttpStatus.BAD_REQUEST.value())
            .message("参数错误")
            .build();

        final ResponseMessage unauthorizedResponse = new ResponseMessageBuilder()
            .code(HttpStatus.UNAUTHORIZED.value())
            .message("认证错误")
            .build();

        final ResponseMessage forbiddenResponse = new ResponseMessageBuilder()
            .code(HttpStatus.FORBIDDEN.value())
            .message("无权限")
            .build();
        return docket.useDefaultResponseMessages(false)
                     .globalResponseMessage(RequestMethod.GET, Arrays.asList(badRequestResponse, unauthorizedResponse, forbiddenResponse))
                     .globalResponseMessage(RequestMethod.POST, Arrays.asList(badRequestResponse, unauthorizedResponse, forbiddenResponse))
                     .globalResponseMessage(RequestMethod.PUT, Arrays.asList(badRequestResponse, unauthorizedResponse, forbiddenResponse))
                     .globalResponseMessage(RequestMethod.DELETE, Arrays.asList(badRequestResponse, unauthorizedResponse, forbiddenResponse))
                     .globalResponseMessage(RequestMethod.PATCH, Arrays.asList(badRequestResponse, unauthorizedResponse, forbiddenResponse));

    }

    /**
     * 解决同时集成spring-boot-starter-actuator、springfox-boot-starter报错问题
     *
     * @return BeanPostProcessor
     */
    @Bean
    public BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() {
        return new BeanPostProcessor() {
            @Override
            @SuppressWarnings({"NullableProblems", "unchecked"})
            public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
                if (bean instanceof WebMvcRequestHandlerProvider) {
                    try {
                        Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");
                        if (null != field) {
                            field.setAccessible(true);
                            List<RequestMappingInfoHandlerMapping> mappings = (List<RequestMappingInfoHandlerMapping>) field.get(bean);
                            mappings.removeIf(e -> null != e.getPatternParser());
                        }
                    } catch (IllegalArgumentException | IllegalAccessException e) {
                        throw new IllegalStateException(e);
                    }
                }
                return bean;
            }
        };
    }
}
